package futbol.tacticas.concursantes.PistolerosDeGilead;

import futbol.General;
import futbol.tacticas.Comando;
import futbol.tacticas.ComandoGolpearBola;
import futbol.tacticas.ComandoIrA;
import futbol.tacticas.ComandoTiroAPuerta;
import futbol.tacticas.SituacionJugadores;
import futbol.tacticas.concursantes.Tactica;

import java.awt.Color;
import java.awt.Point;
import java.util.Vector;

public class PistolerosDeGilead implements Tactica {

    public String getNombre() {
        return "Pistoleros de Gilead";
    }

    public Color getColor1() {
        return Color.BLACK;
    }

    public Color getColor2() {
        return Color.BLACK;
    }

    public Color getColorNumero() {
        return Color.WHITE;
    }
    private static final int LIMITE_EJE_Y_IZQUIERDO_CAMPO = -120;
    private static final int LIMITE_EJE_Y_DERECHO_CAMPO = 120;
    private static final int LIMITE_EJE_X_IZQUIERDO_CAMPO = -160;
    private static final int LIMITE_EJE_X_DERECHO_CAMPO = 160;
    private static final int TOTAL_EJE_Y = 240;
    private static final int TOTAL_EJE_X = 320;
    private static final int VALOR_MAX = 999999;
    int bxActual = 0, byActual = 0, v;
    int bxAnterior = 0, byAnterior = 0;
    int bx2TurnosAnterior = 0, by2TurnosAnterior = 0;
    int _bx, _by;
    int contadorDeIteracion = 0, contador0 = 0;
    int x[] = new int[11];
    int y[] = new int[11];
    int p[] = new int[11];
    double[] velocidadContrarios = new double[11];
    double[] fuerzaContrarios = new double[11];
    Point[] posicionContrarios = new Point[11];
    Vector<Comando> com = new Vector();
    public final int fuerza[] = {7, 7, 6, 6, 6, 6, 7, 7, 7, 7, 7};
    public final int velocidad[] = {3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3};
    private int pos[][] = new int[][]{
        {-140, 0},
        {-110, 0},
        {-60, 60},
        {-60, -60},
        {0, 20},
        {0, -20},
        {50, 50},
        {50, -50},
        {100, 80},
        {120, 0},
        {100, -80}};

    public int getFuerza(int n) {
        return fuerza[n];
    }

    public int getVelocidad(int n) {
        return velocidad[n];
    }

    public int getXInicial(int n) {
        return pos[n][0];
    }

    public int getYInicial(int n) {
        return pos[n][1];
    }

    private double angulo(double dx, double dy) {
        double angulo = 0;
        if (dx > 0) {
            angulo = Math.atan(dy / dx);
        } else if (dx < 0) {
            angulo = Math.atan(dy / dx) + Math.PI;
        } else {
            angulo = -Math.PI / 2;
        }
        return angulo;
    }

    private double distancia(double x1, double y1, double x0, double y0) {
        double dx = (x1 - x0);
        double dy = (y1 - y0);
        return Math.sqrt(dx * dx + dy * dy);
    }

    public Vector<Comando> getComandos(SituacionJugadores sj) {

        com.clear();
        obtenerDatosContrarios(sj);
        tacticaEvolution(sj);
        defensaAlHombre(sj);
        lanzamiento(sj, com);
        //Asignamos al vector PosicionContrarios la posición que tienen en esta iteración
        posicionContrarios = sj.getContrario();
        contadorDeIteracion++;
        return com;
    }

    public void obtenerDatosContrarios(SituacionJugadores sj) {
        if (contadorDeIteracion == 0) {
            posicionContrarios = sj.getContrario();
        } else {
            for (int i = 0; i < 11; i++) {
                double velocidadContrario = Math.round(distancia(posicionContrarios[i].getX(), posicionContrarios[i].getY(), sj.getContrario()[i].getX(), sj.getContrario()[i].getY()));
                if (velocidadContrario < 8 && velocidadContrario > 2) {
                    velocidadContrarios[i] = velocidadContrario;
                }
                fuerzaContrarios[i] = 10 - velocidadContrarios[i];
            }
        }
    }

    private void posicionador() {
        int min = VALOR_MAX;
        for (int i = 0; i < 11; i++) {
            if (p[i] < min) {
                min = p[i];
            }
        }
        for (int i = 0; i < 11; i++) {
            if (min == p[i]) {
                com.add(new ComandoIrA(i, x[i], y[i]));
            } else {
                com.add(new ComandoIrA(i, getXInicial(i), getYInicial(i)));
            }
        }
    }

    private void tacticaEvolution(SituacionJugadores sj) {
        bx2TurnosAnterior = bxAnterior;
        by2TurnosAnterior = byAnterior;

        bxAnterior = bxActual;
        byAnterior = byActual;

        Point b = sj.getBola();
        bxActual = b.x;
        byActual = b.y;

        double d0 = distancia(bx2TurnosAnterior, by2TurnosAnterior, bxAnterior, byAnterior);
        double d1 = distancia(bxAnterior, byAnterior, bxActual, byActual);
        double a0 = angulo(bx2TurnosAnterior - bxAnterior, by2TurnosAnterior - byAnterior);
        double a1 = angulo(bxAnterior - bxActual, byAnterior - byActual);

        if (d0 > 3 && (Math.abs(a0 - a1) > .20 || Math.abs(d0 - d1) > 5)) {
            _bx = bxAnterior;
            _by = byAnterior;
            contador0 = contadorDeIteracion - 1;
        }

        double n = (double) (contadorDeIteracion - contador0);
        double d = distancia(bxActual, byActual, _bx, _by);
        double dx = (double) (bxActual - _bx) / d;
        double dy = (double) (byActual - _by) / d;

        v = Math.max((int) Math.round(d / n - (n + 1d) / 2d), 0);

        int[] bx = new int[v + 1];
        int[] by = new int[v + 1];
        bx[v] = bxActual;
        by[v] = byActual;

        for (int i = v; i > 0; i--) {
            bx[i - 1] = bx[i] + (int) Math.round(dx * (double) i);
            by[i - 1] = by[i] + (int) Math.round(dy * (double) i);
            if (by[i - 1] < LIMITE_EJE_Y_IZQUIERDO_CAMPO) {
                by[i - 1] = -TOTAL_EJE_Y - by[i - 1];
                dy = -dy;
            }
            if (by[i - 1] > LIMITE_EJE_Y_DERECHO_CAMPO) {
                by[i - 1] = TOTAL_EJE_Y - by[i - 1];
                dy = -dy;
            }
            if (bx[i - 1] < LIMITE_EJE_X_IZQUIERDO_CAMPO) {
                bx[i - 1] = -TOTAL_EJE_X - bx[i - 1];
                dx = -dx;
            }
            if (bx[i - 1] > LIMITE_EJE_X_DERECHO_CAMPO) {
                bx[i - 1] = TOTAL_EJE_X - bx[i - 1];
                dx = -dx;
            }
        }


        for (int i = 0; i < 11; i++) {
            int jm = Math.max(Math.min(14, v - 1), 0);
            int bx_ = sj.getMisJugadores()[i].x;
            int by_ = sj.getMisJugadores()[i].y;
            d1 = getVelocidad(i);
            boolean entraEnIf = false;
            for (int j = jm; j > 0; j--) {
                d0 = Math.max(0, distancia(bx_, by_, bx[j], by[j]) - 10d) / d1;
                if (d0 < (v - j)) {
                    p[i] = v - j;
                    x[i] = bx[j];
                    y[i] = by[j];
                    entraEnIf = true;
                    break;
                }
            }

            if (!entraEnIf) {
                d0 = Math.max(0, distancia(bx_, by_, bx[0], by[0]) - 10d) / d1;
                if ((d0 - Math.floor(d0)) > 0) {
                    d0 = Math.floor(d0) + 1;
                } else {
                    d0 = Math.floor(d0);
                }
                p[i] = (int) d0;
                x[i] = bx[0];
                y[i] = by[0];
            }
        }
        posicionador();
    }

    private void defensaAlHombre(SituacionJugadores sj) {
        Point bola = sj.getBola();
        Point jugadores[] = sj.getMisJugadores();
        Point contrarios[] = sj.getContrario();

        if (!sj.estoyMasCercaDeBola() || bola.getX() < 0) {
            int nJC = sj.getContrarioMasCerca(jugadores[1].getX(), jugadores[1].getY());
            if (contrarios[nJC].getY() > 40 || contrarios[nJC].getY() < -40 || contrarios[nJC].getX() > -40) {
                com.add(new ComandoIrA(1, getXInicial(1), getYInicial(1)));
            } else if (bola.getX() > contrarios[nJC].getX()) {
                com.add(new ComandoIrA(1, contrarios[nJC].getX() + 10, contrarios[nJC].getY()));
            } else if (bola.getX() < contrarios[nJC].getX()) {
                com.add(new ComandoIrA(1, contrarios[nJC].getX() - 10, contrarios[nJC].getY()));
            }
        }
    }

    private int heuristica(SituacionJugadores sj, int x, int y) {
        int nHeu = y * 5 - x * 100;

        int nDisMenorJugadores = 100;
        int nDisMenorRivales = 100;
        Point jugadores[] = sj.getMisJugadores();
        for (int n = 0; n < 11; n++) {
            int nDis = (int) (General.getDistancia(x, y, jugadores[n].getX(), jugadores[n].getY()));
            if (nDis < nDisMenorJugadores) {
                nDisMenorJugadores = nDis;
            }
            if (nDis < 70) {
                nHeu -= 1000;
            }
        }

        Point contrarios[] = sj.getContrario();
        for (int n = 0; n < 11; n++) {
            int nDis = (int) (General.getDistancia(x, y, contrarios[n].getX(), contrarios[n].getY()));
            if (nDis < nDisMenorRivales) {
                nDisMenorRivales = nDis;
            }
            if (nDis < 70) {
                nHeu += 1000;
            }
        }

        if (nDisMenorJugadores < nDisMenorRivales) {
            nHeu -= 1000;
            if (nDisMenorJugadores < 50) {
                nHeu -= 1000;
            } else if (nDisMenorJugadores < 30) {
                nHeu -= 3000;
            } else if (nDisMenorJugadores < 10) {
                nHeu -= 5000;
            }

        }

        return nHeu;
    }

    private void lanzamiento(SituacionJugadores sj, Vector<Comando> com) {
        int nHeuMejor = 9999999;
        int xMej = 0, yMej = 0;
        int x2 = 0, y2 = 0, nHeu;
        for (int n = 0; n < 1000; n++) {
            x2 = (int) (Math.random() * 340) - 170;
            y2 = (int) (Math.random() * 240) - 120;
            nHeu = heuristica(sj, x2, y2);
            if (nHeuMejor > nHeu) {
                nHeuMejor = nHeu;
                xMej = x2;
                yMej = y2;
            }
        }

        Point jugadores[] = sj.getMisJugadores();
        for (int n = 0; n <
                11; n++) {
            if (jugadores[n].getX() > 50) {
                int desvio = 0;
                int rand = (int) Math.random() * 100 % 2;
                if (jugadores[n].getY() > 30 && rand == 0) {
                    desvio = 10;
                } else if (jugadores[n].getY() > 30 && rand == 1) {
                    desvio = -10;
                } else if (jugadores[n].getY() < -30 && rand == 0) {
                    desvio = -10;
                } else if (jugadores[n].getY() < -30 && rand == 1) {
                    desvio = 10;
                }
                com.add(new ComandoTiroAPuerta(n, desvio));
            } else {
                com.add(new ComandoGolpearBola(n, xMej, yMej));
            }
        }
    }
}
